package com.mystnihon.freeremote.util;

import java.lang.ref.WeakReference;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class FTimer {

	public static interface FTimerListener {
		/**
		 * Callback when the Timer refresh time passed. Then you could reset the
		 * timer by calling {@link #FTimer.reset()} to receive again a timer
		 * tick after the default refresh time
		 */
		public void onTick();
	}

	private long mRefreshTime;
	private long mLastRefreshTime;
	private FTimer.FTimerListener mFTimerListener;

	private static final String TAG = FTimer.class.getSimpleName();
	private static final int MESSAGE_ID = 1;
	private static final String STATE_LAST_REFRESH_TIME = "com.mystnihon.freeremote.LastRefreshTime";
	private final WeakHandler mHandler = new WeakHandler(this);

	public void onSaveInstanceState(Bundle outState) {
		if (outState != null) {
			outState.putLong(STATE_LAST_REFRESH_TIME, mLastRefreshTime);
		}
	}

	public void onRestoreInstanceState(Bundle savedInstanceState) {
		if (savedInstanceState != null) {
			setLastRefreshTime(savedInstanceState.getLong(STATE_LAST_REFRESH_TIME));
		} else {
			setLastRefreshTime(0);
		}
	}

	/**
	 * Set the default refresh time when after which you'll receive a timer
	 * tick. Time in milliseconds.
	 * 
	 * @param refreshTime
	 */
	public void setRefreshTime(long refreshTime) {
		mRefreshTime = refreshTime;
	}

	/**
	 * You should call this method to prepare the timer after
	 * {@link #setRefreshTime(long)}. It will start the timer.
	 */
	public void initialize() {
		Log.d(TAG, "initialize");
		final long remaining = mLastRefreshTime + mRefreshTime - System.currentTimeMillis();
		if (remaining <= 0) {
			callListeners();
		} else {
			setNextRefresh(remaining);
		}
	}

	/**
	 * Reset timer and set the next time timer tick to the specified time.
	 * Should be use to set a custom refresh time. If you want to prepare the
	 * next tick using default refresh time use reset instead.
	 * 
	 * @param time
	 *            when you'll receive a timer tick in milliseconds
	 */
	public void setNextRefresh(long time) {
		if (time > 0) {
			cleanMessages();
			mHandler.sendEmptyMessageDelayed(MESSAGE_ID, time);
		}
	}

	/**
	 * Reset the timer and record the next timer tick for the refresh time
	 * specified by {@link #setRefreshTime(long)}
	 */
	public void reset() {
		setNextRefresh(mRefreshTime);
	}

	public void cleanMessages() {
		if (mHandler.hasMessages(MESSAGE_ID)) {
			mHandler.removeMessages(MESSAGE_ID);
		}
	}

	public void setLastRefreshTime(long lastRefreshTime) {
		mLastRefreshTime = lastRefreshTime;
	}

	public void setFTimerListener(FTimer.FTimerListener fTimerListener) {
		mFTimerListener = fTimerListener;
	}

	/**
	 * Get the configured refresh time.
	 * 
	 * @return
	 */
	public long getRefreshTime() {
		return mRefreshTime;
	}

	public long getLastRefreshTime() {
		return mLastRefreshTime;
	}

	private void callListeners() {
		Log.d(TAG, "callListeners");
		if (mFTimerListener != null) {
			mFTimerListener.onTick();
		}

	};

	static class WeakHandler extends Handler {
		WeakReference<FTimer> reference;

		public WeakHandler(FTimer timer) {
			reference = new WeakReference<FTimer>(timer);
		}

		@Override
		public void handleMessage(Message msg) {
			if (msg.what == MESSAGE_ID) {
				Log.d("mLastRefreshTime", "Handle message");
				reference.get().callListeners();
			}
		};
	}
}